//Christian Larco,  Assignment 8, CPE 301
//THis program is used to get the output of a pot to control the frequency of
//and output sine wave. 

//-------------------- These are the libraries we are going to use -------------------------------------

#define F_CPU 8000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
//------------------------------------------------------------------------------------------------------


//---------------------------------This is the lookup table --------------------------------------------
static const uint8_t sinLUT[] PROGMEM = {
	40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,42,42,
	42,42,42,42,42,43,43,43,43,43,44,44,44,44,45,45,45,46,46,46,46,47,47,48,48,48,49,49,50,50,51,51,
	52,52,53,54,54,55,56,57,58,58,59,61,62,63,64,65,67,69,70,72,74,77,79,82,85,89,94,99,105,112,122,135,
	152,180,235
};
//------------------------------------------------------------------------------------------------------


//-------------------------------This command waits for TWI to finish-----------------------------------
uint8_t waitTwi(){
	while(!(TWCR & (1<<TWINT)));
	return (TWSR&0xF8);
}
//------------------------------------------------------------------------------------------------------

//-------------------------- List of functions we will be using in the program -------------------------
void initializeTw();				// Function to initialize TWI
void devStop();						// Device stop
void devValSets(uint8_t, uint8_t);	// Device start
uint8_t sendTw(uint8_t);			// Sent TWI
void devStart();					// Device start
//-----------------------------------------------------------------------------------------------------

//------------------------ These are the variables ----------------------------------------------------
volatile uint8_t varT = 0; 
volatile uint8_t varV = 0; 
volatile uint8_t varD = 20; 
volatile uint16_t count = 0;
volatile uint8_t selectState = 0;
//-----------------------------------------------------------------------------------------------------


//-----------------------------Code for the ISR -------------------------------------------------------
ISR(TIMER1_COMPA_vect){
	cli();
	
	if(!(ADCSRA&(1<<ADSC))){
		varD = 8+(ADC>>4);
		
		ADCSRA |= 1<<ADEN;
		ADMUX = 0b01000000;
		ADCSRA |= 1<<ADSC;
	}
	
	uint8_t d = pgm_read_word(&sinLUT[(selectState&1)?98-varV:varV]); // Inverse sine Lut
	
	if(varT+varD < d && varT < d-varD){ // Increment the condition
		varT += varD;
		}else{
		varT += varD;
		do{ // Increment variable selectstate to get the next state
			varT -= d;
			varV++;
			
			if(varV >= 99){
				varV = 0;
				selectState = (selectState+1)&3;
			}
			
			d = pgm_read_word(&sinLUT[(selectState&1)?98-varV:varV]); //Inverse sine LUT.
		}while(varT > d);
		uint16_t y = varV;
		switch(selectState){ //Make the output by looking at the scale and the phase
			case 0: y += 99; break;
			case 1: y = 198-y; break;
			case 2: y = 99-y; break;
		}
		y <<= 4;
		count = y;
	}
	sei();
}

//-----------------------------------------------------------------------------------------------

//----------------------------------Main code for the program -----------------------------------
int main(void)
{
	
	ADCSRA |= 1<<ADEN; // Code to start the ADC
	ADMUX = 0b01000000;
	ADCSRA |= 1<<ADSC; // Code to initilize ADC
	TCCR1A = 0b00000000;
	TCCR1B = 0b00001001;
	TIMSK1 = 0b00000010;
	OCR1A = 250;		//Start the timer at 250
	sei();
	initializeTw(); // makes the call to initialize initializeTw()
	devStart(); // Initialize the Transmission
	
	while(1){
		cli();
		uint16_t y = count;
		sei();
		devValSets((uint8_t)((y>>8)&0x0F),(uint8_t)(y&0xFF));
	}
}
//-----------------------------------------------------------------------------------------------


//------------------------------------This code ends the serial transmission ---------------------------
void devStop(){
	if(sendTw(0xF0)!=0x28) return;
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}
//-----------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------------
void devValSets(uint8_t ms, uint8_t ls){
	//devStart();
	if(sendTw(ms&0xF)!=0x28){
		return;
	}
	if(sendTw(ls)!=0x28){
		return;
	}
}

//-------------------------------Initializes TWI--------------------------------------------------------
void initializeTw(){
	TWBR = 0;
	TWSR = 0;
}
//------------------------------------------------------------------------------------------------------

//-------------------------------------This code is to send data to the TWI ----------------------------
uint8_t sendTw(uint8_t data){
	TWDR = data;
	TWCR = (1<<TWINT) | (1<<TWEN);
	return waitTwi();
}
//------------------------------------------------------------------------------------------------------

//--------------------------------------This code starts the signal transmission -----------------------
void devStart(){
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
	if(waitTwi()!=0x08) return;
	if(sendTw(0xC0)!=0x18) return;
}
//------------------------------------------------------------------------------------------------------
